package com.gjzhao.fmmall.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.gjzhao.fmmall.config.MinIoConfig;
import com.gjzhao.fmmall.vo.RespCode;
import com.gjzhao.fmmall.vo.RespResultVO;
import com.gjzhao.fmmall.vo.minio.MinIoUploadVO;
import io.minio.BucketExistsArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.SetBucketPolicyArgs;
import io.minio.http.Method;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * @Description: 图片存储服务 Controller
 *  - minio还可上传文件/excel
 * @Author: gjzhao
 * @Date Created in 2022-01-23 8:24 下午
 */
@RestController
@RequestMapping("/minio")
@Api(value = "图片存储服务数据接口", tags = "图片管理")
public class MinIoController extends BaseController {

    @Autowired
    private MinIoConfig minIoConfig;


    /**
     * 接口作用：前端上传图片，保存图片到minio
     * 业务流程分析：
     * - 1.前端上传文件，调用该接口
     * - 2.获取 MinioClient 客户端对象(初始化连接信息)，判断存储桶是否存在
     *      - 2.1 如果存储桶不存在，先创建存储桶，设置存储桶只读权限/文件名字
     * - 3. 调用minio接口，上传图片
     * - 4.返回图片访问的url,正常回显图片
     *
     * @param file
     * @return
     */
    @PostMapping("/upload")
    @ApiOperation(value = "图片上传")
    public RespResultVO upload(@RequestParam("file") MultipartFile file) {

        MinioClient minioClient = minIoConfig.minioClient();

        try {
            //1.判断minio的存储桶是否存在
            String bucketName = minIoConfig.getBucketName();
            boolean bucketNameIsExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (bucketNameIsExist) {
                //1.1 如果存储桶已经存在，则不进行创建
                logger.info("----minio存储桶存在:{}----", bucketName);
            } else {

                //1.2 如果存储桶已经存在，则进行创建
                logger.info("----minio存储桶：{}不存在，需要进行创建----", bucketName);

                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());

                String policyJson = "{\n" +
                    "  \"Statement\": [\n" +
                    "        {\n" +
                    "            \"Action\": [\n" +
                    "                \"s3:GetBucketLocation\",\n" +
                    "                \"s3:ListBucket\"\n" +
                    "            ],\n" +
                    "            \"Effect\": \"Allow\",\n" +
                    "            \"Principal\": \"*\",\n" +
                    "            \"Resource\": \"arn:aws:s3:::" + bucketName + "\"\n" +
                    "        },\n" +
                    "        {\n" +
                    "            \"Action\": \"s3:GetObject\",\n" +
                    "            \"Effect\": \"Allow\",\n" +
                    "            \"Principal\": \"*\",\n" +
                    "            \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n" +
                    "        }\n" +
                    "    ],\n" +
                    "    \"Version\": \"2012-10-17\"\n" +
                    "}";

                minioClient.setBucketPolicy(
                    SetBucketPolicyArgs.builder().bucket(bucketName).config(policyJson).build()
                );

                logger.info("----minio创建存储桶:{}完成----", bucketName);

            }
            // 上传文件的名字
            String fileName = file.getOriginalFilename();
            // 存储对象名字
            String objectName = DateUtil.format(new Date(), "yyyy-MM-dd") + fileName;
            // 使用putObject上传一个文件到存储桶中
            minioClient.putObject(
                PutObjectArgs
                    .builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .contentType(file.getContentType())
                    .stream(file.getInputStream(), -1, 1024 * 1024 * 10)
                    .build()
            );

            MinIoUploadVO minIoUploadVO = new MinIoUploadVO();
            minIoUploadVO.setFileName(fileName);
            String url = minIoConfig.getEndpoint() + "/" + bucketName + "/" + objectName;
            minIoUploadVO.setUrl(url);

            logger.info("----上传文件到minio存储桶:{}完成,访问路径：{}----", bucketName, url);
            return RespResultVO.success(minIoUploadVO);
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("---上传发生错误:{}--", e.getMessage());
        }

        return RespResultVO.failed(RespCode.FAILED);
    }


    /**
     * 根据图片资源名称删除图片
     * @param objectName
     * @return
     */
    @PostMapping("/delete")
    @ApiOperation(value = "删除图片")
    @ApiImplicitParam(dataType = "string", name = "objectName", value = "图片对象名字", required = true)
    public RespResultVO delete(@RequestParam("objectName") String objectName) {

        MinioClient minioClient = minIoConfig.minioClient();

        String bucketName = minIoConfig.getBucketName();

        try {
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                                .bucket(bucketName)
                                .object(objectName)
                                .build()
            );
            logger.info("------删除图片:{},success----", objectName);
            return RespResultVO.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("------删除图片失败:{}----", e.getMessage());
        }
        return RespResultVO.failed(RespCode.FAILED);
    }


    /**
     * 获取图片url，生成d的url可直接访问图片
     * @param objectName
     * @return
     */
    @GetMapping(value = "/getUrl")
    @ApiOperation(value = "获取图片url")
    public RespResultVO download(@RequestParam("objectName") String objectName) {

        MinioClient minioClient = minIoConfig.minioClient();

        String bucketName = minIoConfig.getBucketName();

        try {

            String url = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                                         .method(Method.GET)
                                         .bucket(bucketName)
                                         .object(objectName)
                                         .expiry(2, TimeUnit.HOURS)
                                         .build()
            );

            logger.info("------图片url:{}----", url);

            if (StrUtil.isNotBlank(url)) {
                return RespResultVO.success(url);
            } else {
                return RespResultVO.failed(RespCode.FAILED, "资源不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("------获取图片地址失败:{}----", e.getMessage());
        }
        return RespResultVO.failed(RespCode.FAILED);
    }

}


